package com.lonewalker.snail.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lonewalker.snail.constant.flow.*;
import com.lonewalker.snail.domain.entity.ProcessNode;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.delegate.ExecutionListener;
import org.camunda.bpm.model.bpmn.Bpmn;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.Process;
import org.camunda.bpm.model.bpmn.instance.*;
import org.camunda.bpm.model.bpmn.instance.bpmndi.BpmnDiagram;
import org.camunda.bpm.model.bpmn.instance.bpmndi.BpmnEdge;
import org.camunda.bpm.model.bpmn.instance.bpmndi.BpmnPlane;
import org.camunda.bpm.model.bpmn.instance.bpmndi.BpmnShape;
import org.camunda.bpm.model.bpmn.instance.camunda.CamundaExecutionListener;
import org.camunda.bpm.model.bpmn.instance.dc.Bounds;
import org.camunda.bpm.model.bpmn.instance.di.Waypoint;

import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * bpmn工具
 *
 * @author lonewalker
 **/
@NoArgsConstructor
@Slf4j
public class BpmnModelUtil {

    public static void main(String[] args) {
        String processDefinition = "[{\n" +
                "\t\"id\": \"root\",\n" +
                "\t\"pIds\": [],\n" +
                "\t\"type\": 1,\n" +
                "\t\"title\": \"发起人\",\n" +
                "\t\"isRoot\": true,\n" +
                "\t\"content\": \"测试一号\",\n" +
                "\t\"groupId\": null,\n" +
                "\t\"groupPid\": null,\n" +
                "\t\"isParent\": true\n" +
                "}, {\n" +
                "\t\"type\": 2,\n" +
                "\t\"title\": \"审批人\",\n" +
                "\t\"content\": \"发起人自己\",\n" +
                "\t\"groupId\": \"root\",\n" +
                "\t\"id\": \"aa58jyno43om4u3x\",\n" +
                "\t\"isParent\": true,\n" +
                "\t\"pIds\": [\"root\"]\n" +
                "}, {\n" +
                "\t\"title\": \"条件1\",\n" +
                "\t\"content\": \"数值输入>=5\",\n" +
                "\t\"id\": \"aphqzxm2d22jw6d9\",\n" +
                "\t\"groupId\": \"a2pj4qrg8t14qiex\",\n" +
                "\t\"type\": 3,\n" +
                "\t\"groupPid\": \"aa58jyno43om4u3x\",\n" +
                "\t\"level\": 1,\n" +
                "\t\"isParent\": true,\n" +
                "\t\"childNode\": {\n" +
                "\t\t\"type\": 2,\n" +
                "\t\t\"title\": \"审批人\",\n" +
                "\t\t\"content\": \"测试二号\",\n" +
                "\t\t\"groupId\": \"aphqzxm2d22jw6d9\",\n" +
                "\t\t\"id\": \"a5xeh9af35nmvs5x\",\n" +
                "\t\t\"pIds\": [\"aphqzxm2d22jw6d9\"]\n" +
                "\t},\n" +
                "\t\"pIds\": [\"aa58jyno43om4u3x\"]\n" +
                "}, {\n" +
                "\t\"type\": 2,\n" +
                "\t\"title\": \"审批人\",\n" +
                "\t\"content\": \"测试二号\",\n" +
                "\t\"groupId\": \"aphqzxm2d22jw6d9\",\n" +
                "\t\"id\": \"a5xeh9af35nmvs5x\",\n" +
                "\t\"pIds\": [\"aphqzxm2d22jw6d9\"]\n" +
                "}, {\n" +
                "\t\"title\": \"默认条件\",\n" +
                "\t\"content\": \" 其他条件进入此流程\",\n" +
                "\t\"id\": \"acg2d2dtbaiy4unx\",\n" +
                "\t\"groupId\": \"a2pj4qrg8t14qiex\",\n" +
                "\t\"type\": 3,\n" +
                "\t\"groupPid\": \"aa58jyno43om4u3x\",\n" +
                "\t\"level\": 2,\n" +
                "\t\"isParent\": true,\n" +
                "\t\"childNode\": {\n" +
                "\t\t\"type\": 2,\n" +
                "\t\t\"title\": \"审批人\",\n" +
                "\t\t\"content\": \"发起人自己\",\n" +
                "\t\t\"groupId\": \"acg2d2dtbaiy4unx\",\n" +
                "\t\t\"id\": \"ahddtojrwppikc73\",\n" +
                "\t\t\"pIds\": [\"acg2d2dtbaiy4unx\"]\n" +
                "\t},\n" +
                "\t\"pIds\": [\"aa58jyno43om4u3x\"]\n" +
                "}, {\n" +
                "\t\"type\": 2,\n" +
                "\t\"title\": \"审批人\",\n" +
                "\t\"content\": \"发起人自己\",\n" +
                "\t\"groupId\": \"acg2d2dtbaiy4unx\",\n" +
                "\t\"id\": \"ahddtojrwppikc73\",\n" +
                "\t\"pIds\": [\"acg2d2dtbaiy4unx\"]\n" +
                "}]";
    }

    /**
     * 节点树转为bpmn
     *
     * @param processNode          节点树
     * @param processDefinitionKey 流程定义key
     * @return bpmn
     */
    public static byte[] convertBpmn(ProcessNode processNode, String processDefinitionKey) {
        if (ObjectUtil.isNull(processNode) || StrUtil.isEmpty(processDefinitionKey)) {
            log.error("不满足转换条件");
            return null;
        }
        Queue<ProcessNode> nodeQueue = new ConcurrentLinkedDeque<>();
        nodeQueue.add(processNode);

        ConcurrentHashMap<String, Object> elementMap = new ConcurrentHashMap<>(16);
        ConcurrentHashMap<String, Object> nodeMap = new ConcurrentHashMap<>(16);


        //创建bpmn定义元素
        Definitions definitions = createDefinitions(elementMap);

        //创建bpmn元素实例
        Process process = createProcess(definitions, processDefinitionKey);
        //创建bpmn图画板
        BpmnPlane plane = createPlane(definitions, process);

        //先处理开始节点
        createStartNode(process, plane, elementMap, nodeMap);
        while (nodeQueue.size() > 0) {
            ProcessNode currentNode = nodeQueue.remove();
            Integer nodeType = currentNode.getType();
            if (ProcessNodeTypeEnum.INITIATOR.getCode().equals(nodeType)) {
                createInitiatorNode(process, plane, currentNode, elementMap, nodeMap);
            } else if (ProcessNodeTypeEnum.APPROVAL.getCode().equals(nodeType) || ProcessNodeTypeEnum.HANDLE.getCode().equals(nodeType)) {
                createUserTask(process, plane, currentNode, elementMap, nodeMap);
            } else if (ProcessNodeTypeEnum.BRANCH.getCode().equals(nodeType)) {
                ProcessNode parentNode = currentNode.getParents().get(0);
                AtomicInteger atomicCount = new AtomicInteger(0);
                for (ProcessNode child : parentNode.getChildren()) {
                    if (nodeMap.containsKey(child.getId())) {
                        atomicCount.incrementAndGet();
                    }
                }
                createExclusiveGateway(process, plane, parentNode, currentNode, atomicCount, elementMap, nodeMap);
            } else if (ProcessNodeTypeEnum.CARBON_COPY.getCode().equals(nodeType)) {
                createSendTask(process, plane, currentNode, elementMap, nodeMap);
            }

            if (CollUtil.isNotEmpty(currentNode.children)) {
                for (ProcessNode child : currentNode.children) {
                    if (!nodeQueue.contains(child)) {
                        nodeQueue.add(child);
                    }
                }
            } else {
                //创建结束节点
                createEndNode(process, plane, currentNode, elementMap, nodeMap);
            }
        }

        BpmnModelInstance bpmnModelInstance = (BpmnModelInstance) elementMap.get(BpmnConstant.MODEL_INSTANCE);
        Bpmn.validateModel(bpmnModelInstance);


        String bpmn = Bpmn.convertToString(bpmnModelInstance);
        System.out.println(bpmn);
        return bpmn.getBytes();
    }

    private static <T extends BpmnModelElementInstance> T createElement(BpmnModelElementInstance parentElement, String id, Class<T> elementClass) {
        T element = parentElement.getModelInstance().newInstance(elementClass);
        if (StrUtil.isNotEmpty(id)) {
            element.setAttributeValue("id", id, true);
        }
        parentElement.addChildElement(element);
        return element;
    }

    private static void createInitiatorNode(Process process, BpmnPlane plane, ProcessNode currentNode, ConcurrentHashMap<String, Object> elementMap, ConcurrentHashMap<String, Object> nodeMap) {
        String id = currentNode.getId();
        UserTask userTask = createElement(process, id, UserTask.class);
        userTask.setName(currentNode.getTitle());
        userTask.setCamundaAssignee(BpmnConstant.START_ASSIGNEE);

        StartEvent startNode = (StartEvent) nodeMap.get(BpmnEnum.START_EVENT_ID.getValue());
        Bounds startBound = (Bounds) elementMap.get(BpmnEnum.SHAPE_START_ID.getValue());
        //创建开始节点到发起人节点的连线
        createSequenceFlow(process, plane, startNode, startBound, BpmnConstant.EMPTY_STR, BpmnConstant.EMPTY_STR, null, elementMap);
        SequenceFlow sequenceFlow = (SequenceFlow) elementMap.get(BpmnConstant.SEQUENCE);
        sequenceFlow.setTarget(userTask);
        System.out.println(sequenceFlow.getId() + "===" + sequenceFlow.getSource().getId() + "-----" + sequenceFlow.getTarget().getId());
        userTask.getIncoming().add(sequenceFlow);


        Waypoint sequencePoint = (Waypoint) elementMap.get(BpmnConstant.SEQUENCE_TARGET_POINT);
        BpmnShape userTaskShape = createElement(plane, id + "_di", BpmnShape.class);
        userTaskShape.setBpmnElement(userTask);
        Bounds bound = createElement(userTaskShape, null, Bounds.class);
        bound.setWidth(BpmnConstant.TASK_BOUND_WIDTH);
        bound.setHeight(BpmnConstant.TASK_BOUND_HEIGHT);
        bound.setX(sequencePoint.getX());
        bound.setY(sequencePoint.getY() - bound.getHeight() / 2);
        userTaskShape.addChildElement(bound);

        nodeMap.put(id, userTask);
        elementMap.put(id, bound);

    }


    private static void createSequenceFlow(Process process, BpmnPlane plane, FlowNode fromNode, Bounds fromBound, String expression, String id, AtomicInteger atomicCount, ConcurrentHashMap<String, Object> elementMap) {
        //TODO 待优化  节点参数塞到elementMap中
        if (StrUtil.isEmpty(id)) {
            id = "Flow_" + IdUtil.createId();
        }
        SequenceFlow sequenceFlow = createElement(process, id, SequenceFlow.class);

        if (StrUtil.isNotEmpty(expression)) {
            ConditionExpression conditionExpression = createElement(sequenceFlow, null, ConditionExpression.class);
            conditionExpression.setTextContent(expression);
            //sequenceFlow.addChildElement(conditionExpression);
        }
        System.out.println("连线id:" + sequenceFlow.getId() + "---起始节点:" + fromNode.getId());
        sequenceFlow.setSource(fromNode);
        fromNode.getOutgoing().add(sequenceFlow);

        BpmnEdge sequenceEdge = createElement(plane, id + "_di", BpmnEdge.class);
        sequenceEdge.setBpmnElement(sequenceFlow);
        Waypoint wayPointOne = createElement(sequenceEdge, null, Waypoint.class);
        Waypoint wayPointTwo = createElement(sequenceEdge, null, Waypoint.class);
        Waypoint wayPointThree = null;
        wayPointOne.setX(fromBound.getX() + fromBound.getWidth());
        wayPointOne.setY(fromBound.getY() + fromBound.getHeight() / 2);
        if (ObjectUtil.isNull(atomicCount)) {
            wayPointTwo.setX(wayPointOne.getX() + BpmnConstant.SEQUENCE_LENGTH);
            wayPointTwo.setY(wayPointOne.getY());
        } else {
            wayPointThree = createElement(sequenceEdge, null, Waypoint.class);
            wayPointTwo.setX(wayPointOne.getX());
            wayPointTwo.setY(wayPointOne.getY() + (100.0 * atomicCount.intValue()));

            wayPointThree.setX(wayPointTwo.getX() + BpmnConstant.SEQUENCE_LENGTH);
            wayPointThree.setY(wayPointTwo.getY());
        }
        elementMap.put(BpmnConstant.SEQUENCE, sequenceFlow);
        if (ObjectUtil.isNull(wayPointThree)) {
            elementMap.put(BpmnConstant.SEQUENCE_TARGET_POINT, wayPointTwo);
        } else {
            elementMap.put(id, wayPointThree);
        }
    }

    private static Definitions createDefinitions(ConcurrentHashMap<String, Object> elementMap) {
        BpmnModelInstance modelInstance = Bpmn.createEmptyModel();
        Definitions definitions = modelInstance.newInstance(Definitions.class);
        definitions.setExporter(BpmnEnum.EXPORTER.getValue());
        definitions.setExporterVersion(BpmnEnum.EXPORTER_VERSION.getValue());
        definitions.setTargetNamespace(BpmnEnum.TARGET_NAMESPACE.getValue());
        modelInstance.setDefinitions(definitions);
        elementMap.put(BpmnConstant.MODEL_INSTANCE, modelInstance);
        return definitions;
    }

    private static Process createProcess(Definitions definitions, String processDefinitionKey) {
        Process process = createElement(definitions, processDefinitionKey, Process.class);
        process.setExecutable(true);
        return process;
    }

    private static BpmnPlane createPlane(Definitions definitions, Process process) {
        BpmnDiagram diagram = createElement(definitions, BpmnEnum.BPMN_DIAGRAM_ID.getValue(), BpmnDiagram.class);
        BpmnPlane bpmnPlane = createElement(diagram, BpmnEnum.BPMN_PLANE_ID.getValue(), BpmnPlane.class);
        bpmnPlane.setBpmnElement(process);
        return bpmnPlane;
    }

    private static void createStartNode(Process process, BpmnPlane plane, ConcurrentHashMap<String, Object> elementMap, ConcurrentHashMap<String, Object> nodeMap) {
        StartEvent startEvent = createElement(process, BpmnEnum.START_EVENT_ID.getValue(), StartEvent.class);
        BpmnShape startShape = createElement(plane, BpmnEnum.SHAPE_START_ID.getValue(), BpmnShape.class);
        startShape.setBpmnElement(startEvent);
        Bounds bound = createElement(startShape, null, Bounds.class);
        bound.setX(BpmnConstant.START_NODE_X);
        bound.setY(BpmnConstant.START_NODE_Y);
        bound.setWidth(BpmnConstant.START_BOUND_WIDTH);
        bound.setHeight(BpmnConstant.START_BOUND_HEIGHT);
        startShape.addChildElement(bound);

        nodeMap.put(BpmnEnum.START_EVENT_ID.getValue(), startEvent);
        elementMap.put(BpmnEnum.SHAPE_START_ID.getValue(), bound);
    }

    private static void createEndNode(Process process, BpmnPlane plane, ProcessNode parent, ConcurrentHashMap<String, Object> elementMap, ConcurrentHashMap<String, Object> nodeMap) {
        EndEvent endEvent;
        String parentId = parent.getId();
        String id = "";
        if (nodeMap.containsKey(BpmnConstant.END_NODE)) {
            endEvent = (EndEvent) nodeMap.get(BpmnConstant.END_NODE);
        } else {
            id = "Event" + IdUtil.createId();
            endEvent = createElement(process, id, EndEvent.class);
        }


        Integer parentType = parent.getType();
        SequenceFlow sequenceFlow;
        if (ProcessNodeTypeEnum.BRANCH.getCode().equals(parentType)) {
            sequenceFlow = (SequenceFlow) nodeMap.get(parentId);
        } else {
            FlowNode parentNode = (FlowNode) nodeMap.get(parentId);
            Bounds parentBound = (Bounds) elementMap.get(parentId);
            createSequenceFlow(process, plane, parentNode, parentBound, BpmnConstant.EMPTY_STR, BpmnConstant.EMPTY_STR, null, elementMap);
            sequenceFlow = (SequenceFlow) elementMap.get(BpmnConstant.SEQUENCE);

        }
        sequenceFlow.setTarget(endEvent);
        process.addChildElement(sequenceFlow);
        endEvent.getIncoming().add(sequenceFlow);


        if (!nodeMap.containsKey(BpmnConstant.END_NODE)) {
            Waypoint sequencePoint = (Waypoint) elementMap.get(BpmnConstant.SEQUENCE_TARGET_POINT);
            BpmnShape endShape = createElement(plane, id + "_di", BpmnShape.class);
            endShape.setBpmnElement(endEvent);
            Bounds bound = createElement(endShape, null, Bounds.class);
            bound.setWidth(BpmnConstant.START_BOUND_WIDTH);
            bound.setHeight(BpmnConstant.START_BOUND_HEIGHT);
            bound.setX(sequencePoint.getX());
            bound.setY(sequencePoint.getY() - bound.getHeight() / 2);
            endShape.addChildElement(bound);
        }

        nodeMap.put(BpmnConstant.END_NODE, endEvent);

    }


    private static void createUserTask(Process process, BpmnPlane plane, ProcessNode currentNode,
                                       ConcurrentHashMap<String, Object> elementMap, ConcurrentHashMap<String, Object> nodeMap) {
        String id = currentNode.getId();

        //创建用户任务
        UserTask userTask;
        if (nodeMap.containsKey(id)) {
            userTask = (UserTask) nodeMap.get(id);
        } else {
            userTask = createElement(process, id, UserTask.class);
            userTask.setName(currentNode.getTitle());
            userTask.setCamundaAssignee(BpmnConstant.USER_TASK_ASSIGNEE);
            MultiInstanceLoopCharacteristics multiInstanceLoop = createElement(userTask, null, MultiInstanceLoopCharacteristics.class);
            multiInstanceLoop.setCamundaCollection(BpmnConstant.MULTI_INSTANCE_COLLECTION);
            multiInstanceLoop.setCamundaElementVariable(BpmnConstant.ELEMENT_VARIABLE);
            //判断或签还是会签
            CompletionCondition completionCondition = createElement(multiInstanceLoop, null, CompletionCondition.class);
            if (ApprovalModeEnum.OR_SIGN.getCode().equals(currentNode.getApprovalMode())) {
                completionCondition.setTextContent(BpmnConstant.COMPLETION_CONDITION_ONE);
            } else {
                if (ApprovalModeEnum.SEQUENTIAL.getCode().equals(currentNode.getApprovalMode())){
                    //设置任务为串行
                    multiInstanceLoop.setSequential(true);
                }
                completionCondition.setTextContent(BpmnConstant.COMPLETION_CONDITION_ALL);
            }
            multiInstanceLoop.setCompletionCondition(completionCondition);
        }


        //创建父节点与当前节点的连线
        for (ProcessNode parent : currentNode.getParents()) {
            if (ProcessNodeTypeEnum.BRANCH.getCode().equals(parent.getType())) {
                //父节点是分支节点则只会有一个
                SequenceFlow sequenceFlow = (SequenceFlow) nodeMap.get(parent.getId());
                //创建连线扩展元素-执行监听器
                createSequenceExtension(sequenceFlow);
                sequenceFlow.setTarget(userTask);
                process.addChildElement(sequenceFlow);
                userTask.getIncoming().add(sequenceFlow);
            } else {
                FlowNode parentNode = (FlowNode) nodeMap.get(parent.getId());
                Bounds parentBound = (Bounds) elementMap.get(parent.getId());
                createSequenceFlow(process, plane, parentNode, parentBound, BpmnConstant.EMPTY_STR, BpmnConstant.EMPTY_STR, null, elementMap);
                SequenceFlow sequenceFlow = (SequenceFlow) elementMap.get(BpmnConstant.SEQUENCE);
                //创建连线扩展元素-执行监听器
                createSequenceExtension(sequenceFlow);
                sequenceFlow.setTarget(userTask);
                System.out.println("源头：" + sequenceFlow.getSource().getId() + "---目标:" + sequenceFlow.getTarget().getId());
                process.addChildElement(sequenceFlow);
                userTask.getIncoming().add(sequenceFlow);
            }
        }


//        String parentType = currentNode.getParent().get(0).getType();
//        if (ProcessNodeTypeEnum.BRANCH.getCode().equals(parentType)){
//            //父节点是分支节点则只会有一个
//            SequenceFlow sequenceFlow = (SequenceFlow) nodeMap.get(currentNode.getParent().get(0).getId());
//            //创建连线扩展元素-执行监听器
//            createSequenceExtension(sequenceFlow);
//            sequenceFlow.setTarget(userTask);
//            process.addChildElement(sequenceFlow);
//            userTask.getIncoming().add(sequenceFlow);
//        }else{
//            for (ProcessNode parent : currentNode.getParent()) {
//                FlowNode parentNode = (FlowNode) nodeMap.get(parent.getId());
//                Bounds parentBound = (Bounds) elementMap.get(parent.getId());
//                createSequenceFlow(process, plane, parentNode, parentBound, BpmnConstant.EMPTY_STR,BpmnConstant.EMPTY_STR, null,elementMap);
//                SequenceFlow sequenceFlow = (SequenceFlow) elementMap.get(BpmnConstant.SEQUENCE);
//                //创建连线扩展元素-执行监听器
//                createSequenceExtension(sequenceFlow);
//                sequenceFlow.setTarget(userTask);
//                System.out.println("源头："+sequenceFlow.getSource().getId()+"---目标:"+sequenceFlow.getTarget().getId());
//                process.addChildElement(sequenceFlow);
//                userTask.getIncoming().add(sequenceFlow);
//            }
//        }

        Waypoint sequencePoint;
        if (ProcessNodeTypeEnum.BRANCH.getCode().equals(currentNode.getParents().get(0).getType()) && elementMap.containsKey(currentNode.getParents().get(0).getId())) {
            sequencePoint = (Waypoint) elementMap.get(currentNode.getParents().get(0).getId());
        } else {
            sequencePoint = (Waypoint) elementMap.get(BpmnConstant.SEQUENCE_TARGET_POINT);
        }
        BpmnShape userTaskShape = createElement(plane, id + "_di", BpmnShape.class);
        userTaskShape.setBpmnElement(userTask);
        Bounds bound = createElement(userTaskShape, null, Bounds.class);
        bound.setWidth(BpmnConstant.TASK_BOUND_WIDTH);
        bound.setHeight(BpmnConstant.TASK_BOUND_HEIGHT);
        bound.setX(sequencePoint.getX());
        bound.setY(sequencePoint.getY() - bound.getHeight() / 2);
        userTaskShape.addChildElement(bound);

        nodeMap.put(id, userTask);
        elementMap.put(id, bound);

    }

    private static void createSendTask(Process process, BpmnPlane plane, ProcessNode currentNode, ConcurrentHashMap<String, Object> elementMap, ConcurrentHashMap<String, Object> nodeMap) {
        String id = currentNode.getId();

        //创建用户任务
        SendTask sendTask;
        if (nodeMap.containsKey(id)) {
            sendTask = (SendTask) nodeMap.get(id);
        } else {
            sendTask = createElement(process, id, SendTask.class);
            sendTask.setName(currentNode.getTitle());
        }

        sendTask.setImplementation("Java Class");
        sendTask.setCamundaClass(BpmnConstant.SEND_TASK_DELEGATE);

        //创建父节点与当前节点的连线
        Integer parentType = currentNode.getParents().get(0).getType();
        if (ProcessNodeTypeEnum.BRANCH.getCode().equals(parentType)) {
            //父节点是分支节点则只会有一个
            SequenceFlow sequenceFlow = (SequenceFlow) nodeMap.get(currentNode.getParents().get(0).getId());
            sequenceFlow.setTarget(sendTask);
            process.addChildElement(sequenceFlow);
            sendTask.getIncoming().add(sequenceFlow);
        } else {
            for (ProcessNode parent : currentNode.getParents()) {
                FlowNode parentNode = (FlowNode) nodeMap.get(parent.getId());
                Bounds parentBound = (Bounds) elementMap.get(parent.getId());
                createSequenceFlow(process, plane, parentNode, parentBound, BpmnConstant.EMPTY_STR, BpmnConstant.EMPTY_STR, null, elementMap);
                SequenceFlow sequenceFlow = (SequenceFlow) elementMap.get(BpmnConstant.SEQUENCE);
                sequenceFlow.setTarget(sendTask);
                System.out.println("源头：" + sequenceFlow.getSource().getId() + "---目标:" + sequenceFlow.getTarget().getId());
                process.addChildElement(sequenceFlow);
                sendTask.getIncoming().add(sequenceFlow);
            }
        }

        Waypoint sequencePoint;
        if (ProcessNodeTypeEnum.BRANCH.getCode().equals(currentNode.getParents().get(0).getType()) && elementMap.containsKey(currentNode.getParents().get(0).getId())) {
            sequencePoint = (Waypoint) elementMap.get(currentNode.getParents().get(0).getId());
        } else {
            sequencePoint = (Waypoint) elementMap.get(BpmnConstant.SEQUENCE_TARGET_POINT);
        }
        BpmnShape userTaskShape = createElement(plane, id + "_di", BpmnShape.class);
        userTaskShape.setBpmnElement(sendTask);
        Bounds bound = createElement(userTaskShape, null, Bounds.class);
        bound.setWidth(BpmnConstant.TASK_BOUND_WIDTH);
        bound.setHeight(BpmnConstant.TASK_BOUND_HEIGHT);
        bound.setX(sequencePoint.getX());
        bound.setY(sequencePoint.getY() - bound.getHeight() / 2);
        userTaskShape.addChildElement(bound);

        nodeMap.put(id, sendTask);
        elementMap.put(id, bound);
    }

    /**
     * 创建排他网关
     */
    private static void createExclusiveGateway(Process process, BpmnPlane plane, ProcessNode parent, ProcessNode currentNode, AtomicInteger atomicCount,
                                               ConcurrentHashMap<String, Object> elementMap, ConcurrentHashMap<String, Object> nodeMap) {
        String parentId = parent.getId();
        ExclusiveGateway exclusiveGateway;
        Bounds gatewayBound;
        SequenceFlow sequenceFlow;
        if (elementMap.containsKey((parentId + "_Gateway"))) {
            exclusiveGateway = (ExclusiveGateway) elementMap.get(parentId + "_Gateway");
            gatewayBound = (Bounds) elementMap.get(parentId + "_GatewayBound");
        } else {
            exclusiveGateway = createElement(process, null, ExclusiveGateway.class);
            Waypoint sequencePoint;
            //判断父节点是否为分支节点
            if (ProcessNodeTypeEnum.BRANCH.getCode().equals(parent.getType())) {
                sequenceFlow = (SequenceFlow) nodeMap.get(parentId);
                sequencePoint = (Waypoint) elementMap.get(parentId);
            } else {
                FlowNode parentNode = (FlowNode) nodeMap.get(parentId);
                Bounds parentBound = (Bounds) elementMap.get(parentId);
                createSequenceFlow(process, plane, parentNode, parentBound, BpmnConstant.EMPTY_STR, BpmnConstant.EMPTY_STR, null, elementMap);
                sequenceFlow = (SequenceFlow) elementMap.get(BpmnConstant.SEQUENCE);
                sequencePoint = (Waypoint) elementMap.get(BpmnConstant.SEQUENCE_TARGET_POINT);
            }
            BpmnShape exclusiveGatewayShape = createElement(plane, "Gateway_" + IdUtil.createId(), BpmnShape.class);
            exclusiveGatewayShape.setBpmnElement(exclusiveGateway);
            gatewayBound = createElement(exclusiveGatewayShape, null, Bounds.class);
            gatewayBound.setWidth(BpmnConstant.GATEWAY_WIDTH);
            gatewayBound.setHeight(BpmnConstant.GATEWAY_HEIGHT);
            gatewayBound.setX(sequencePoint.getX());
            gatewayBound.setY(sequencePoint.getY() - gatewayBound.getHeight() / 2);
            exclusiveGatewayShape.addChildElement(gatewayBound);
            elementMap.put(parentId + "_Gateway", exclusiveGateway);
            elementMap.put(parentId + "_GatewayBound", gatewayBound);
            sequenceFlow.setTarget(exclusiveGateway);
            exclusiveGateway.getIncoming().add(sequenceFlow);
        }

        String expression = StrUtil.isNotBlank(currentNode.getConditionExpression()) ? currentNode.getConditionExpression() : ProcessConstant.EMPTY;

        createSequenceFlow(process, plane, exclusiveGateway, gatewayBound, expression, currentNode.getId(), atomicCount, elementMap);
        sequenceFlow = (SequenceFlow) elementMap.get(BpmnConstant.SEQUENCE);
        exclusiveGateway.getOutgoing().add(sequenceFlow);
        sequenceFlow.setSource(exclusiveGateway);
        nodeMap.put(currentNode.getId(), sequenceFlow);

        if (StrUtil.isEmpty(expression)) {
            exclusiveGateway.setDefault(sequenceFlow);
        }
    }


    /**
     * 创建连线的扩展元素--执行监听器
     */
    private static void createSequenceExtension(SequenceFlow sequenceFlow) {
        ExtensionElements extensionElement = createElement(sequenceFlow, "", ExtensionElements.class);
        CamundaExecutionListener executionListener = createElement(extensionElement, "", CamundaExecutionListener.class);
        executionListener.setCamundaClass(BpmnConstant.EXECUTION_LISTENER);
        executionListener.setCamundaEvent(ExecutionListener.EVENTNAME_TAKE);
    }
}
